module scene.game.mirmap;

import std.c.string : memcpy, memmove, memset;
import std.datetime, std.stream;

import mirdefine, mirshare;
import common.imagearray, common.imagehandler;

import share.types;

import allegro5.allegro;





const MAPDIR = "./Map/";


public struct LightInfo
{
    public bool IsLight;
    public int LightSizeType;
    public int LightColorType;
}

// ¸ÊÆÄÀÏ ·Îµù°ü·Ã Á¤º¸ÀúÀå.
// ÇöÀç ÀÖ´Â Áö¿ªÀÇ ÀüÃ¼ ¸Ê¿¡ °ü·ÃµÈ »çÇ×À» º¸°üÇÑ´Ù.
align(1) public struct MapHeader
{
align(1):
    public char Title[20];
    public ushort wAttr;
    public ushort Width;
    public ushort Height;
    public char cEventFileIdx;
    public char cFogColor;
}

align(1) public struct MapTileInfo
{
align(1):
    public ubyte bFileIdx;
    public ushort wTileIdx;
}
public alias MapTileInfo* PMapTileInfo;

align(1) public struct MapCellInfo
{
align(1):
    public ubyte bFlag;
    public ubyte bObj1Ani;
    public ubyte bObj2Ani;
    public ubyte bFileIdx;
    public ubyte bFileIdx2; //?
    public ushort wObj1;
    public ushort wObj2;
    public ubyte DoorIndex;
    public ubyte DoorOffset;
    public ushort wLigntNEvent;
    public ubyte wLigntNEvent2; //?
}
public alias MapCellInfo* PMapCellInfo;

/*
struct DoorImageInfo
{
    public ushort wPosX;
    public ushort wPosY;
    public ushort wImageNum;
}

struct DoorInfo
{
    public ubyte bDoorIdx;
    public ubyte bDoorImgCnt;
    public DoorImageInfo stDoorImgInfo;
}
*/


public class MirMap
{
    public MapTileInfo[] TileInfoArr;
    public MapCellInfo[] CellInfoArr;
    
    public MapHeader Header;                        // ·ÎµùµÈ ¸ÊÆÄÀÏÀÇ Çì´õ.
    
    // Ä³¸¯ÅÍÀÇ ÀÌµ¿°ú °ü·ÃµÈ´Ù.
    public int m_shStartViewTileX;                  // ºä¿µ¿ªÀÇ ½ÃÀÛ X Tile ÁÂÇ¥.(½ÇÁ¦ ½ºÅ©¸° ½ÃÀÛ Å¸ÀÏ ÁÂÇ¥º¸´Ù Á¶±Ý ´õ Å« »çÀÌÁîÀÌ´Ù.)
    public int m_shStartViewTileY;                  // ºä¿µ¿ªÀº ½ÇÁ¦ ½ºÅ©¸° ¿µ¿ªº¸´Ù °¡·Î, ¼¼·Î 1Å¸ÀÏ¾¿À» ¿©ºÐÀ¸·Î µÐ´Ù.
    public int m_shViewOffsetX;                     // ½ºÅ©·ÑÇÑ XÃàÇÑ ±æÀÌ.(Ä³¸¯ÅÍÀÇ °È±âµ¿ÀÛÀÇ ÇÁ·¹ÀÓ.)
    public int m_shViewOffsetY;                
    
    public IntRectangle m_rcView;                   // ¸Ê±âº»Å¸ÀÏÀÌ ±×·ÁÁú ¿µ¿ª.(È­¸éÅ¬¸®ÇÎÀ» À§ÇØ¼­)
    
    public IntPoint m_ptMovePixelArray[6];          // ÀÌµ¿À» À§ÇÑ ÇÈ¼¿°ªÀÇ º¸°üµ¥ÀÌÅ¸.
    
    public ushort m_wSavedMapBuffer[(_VIEW_CELL_X_COUNT*_CELL_WIDTH) * (_VIEW_CELL_Y_COUNT*_CELL_HEIGHT)];              // ±âº»Å¸ÀÏ°ú SMÅ¸ÀÏÀ» ±â·ÏÇÑ ¹öÆÛ. ÀÚ±â Ä³¸¯ÅÍ°¡ ÀÌµ¿ÇÏ±âÀü¿£ °»½ÅµÇÁö ¾Ê´Â´Ù.
    
    
    public uint m_dwAniSaveTime[8];
    public ubyte m_bAniTileFrame[8][16];
    
    public ImageArray m_pxTileImg[_MAX_TILE_FILE];
    /*
    public ubyte m_bDoorCount;
    public DoorInfo[] m_pstDoorInfo;
    public ubyte[] m_pbCellIDoorIdx;
*/

    public bool _dirty;
    
    public this()
    {
        InitMapHandler();
    }
    
    public ~this()
    {
        DestroyMapHandler();
    }
    
    // Å¬·¡½º Á¤º¸ ÃÊ±âÈ­.
    public void InitMapHandler()
    {
        TileInfoArr = null;
        CellInfoArr = null;
        //m_pstDoorInfo = null;
        //m_pbCellIDoorIdx = null;
        
        m_shStartViewTileX = 0;    
        m_shStartViewTileY = 0;
        m_shViewOffsetX = 0;
        m_shViewOffsetY = 0;
        //m_bDoorCount = 0;
        
        m_ptMovePixelArray[0].setX(8); m_ptMovePixelArray[0].setY(5);
        m_ptMovePixelArray[1].setX(16); m_ptMovePixelArray[1].setY(11);
        m_ptMovePixelArray[2].setX(24); m_ptMovePixelArray[2].setY(16);
        m_ptMovePixelArray[3].setX(32); m_ptMovePixelArray[3].setY(21);
        m_ptMovePixelArray[4].setX(40); m_ptMovePixelArray[4].setY(27);
        m_ptMovePixelArray[5].setX(48); m_ptMovePixelArray[5].setY(32);
        
        //m_wSavedMapBitmap = al_create_bitmap(_VIEW_CELL_X_COUNT*_CELL_WIDTH, _VIEW_CELL_Y_COUNT*_CELL_HEIGHT);
        // TODO:
        //m_wSavedMapBuffer = m_wSavedMapBuffer.init;
        memset(m_wSavedMapBuffer, 0, m_wSavedMapBuffer.sizeof);
        m_bAniTileFrame = m_bAniTileFrame.init;
        m_dwAniSaveTime = m_dwAniSaveTime.init;
        Header = Header.init;
        
        m_rcView = IntRectangle(0, 0, _VIEW_CELL_X_COUNT*_CELL_WIDTH, _VIEW_CELL_Y_COUNT*_CELL_HEIGHT);
        
        m_pxTileImg = m_pxTileImg.init;

        _dirty = false;
    }
    
    // ÀÌ¹ÌÁö¹× °¢Á¾ ¸Ê¿ëµ¥ÀÌÅ¸ ·Îµå.
    public void LoadMapHandler(string mapname, int nX, int nY)
    {
        InitMapHandler();
        LoadMapData(mapname);
        SetStartViewTile(nX, nY);
        LoadNewMapBuffer();
    }
    
    // Å¬·¡½º Á¤º¸ ÃÊ±âÈ­¹× ¸Þ¸ð¸® ÇØÁ¦.
    public void DestroyMapHandler()
    {
        //  INT nCnt;
        
        destroy(TileInfoArr);
        destroy(CellInfoArr);
        /*  for ( nCnt = 0; nCnt < m_bDoorCount; nCnt++ )
        {
            SAFE_DELETE(m_pstDoorInfo[nCnt].pstDoorImgInfo);
        }
        SAFE_DELETE(m_pstDoorInfo);
        SAFE_DELETE(m_pbCellIDoorIdx);*/
        
        InitMapHandler();
    }

    public bool DrawWithImageForCompMemToMem(int nX, int nY, int nXSize, int nYSize, ushort[] pwSrc, int nDstXSize, int nDstYSize, ushort[] pwDst, ushort wChooseColor1 = 0XFFFF, ushort wChooseColor2 = 0XFFFF)
    {
        IntRectangle rc;
        
        int nWidth = nXSize;
        int nHeight = nYSize;
        int nXOffset = 0;
        int nYOffset = 0;
        int nStartX = 0;
        int nStartY = 0;
        int nEndX = nDstXSize - 1;
        int nEndY = nDstYSize - 1;
        
        if ( pwDst.length > 0 )
        {
            if (nX < nStartX )
            { 
                nXOffset = nStartX - nX;
                nWidth = nXSize - nXOffset;
            }
            if ( (nX+nXSize-1) > nEndX )
                nWidth = nEndX - nX - nXOffset + 1;        
            if ( nY < nStartY )     { 
                nYOffset = nStartY - nY;
                nHeight = nYSize - nYOffset;
            }       
            if ( (nY+nYSize-1) > nEndY )
                nHeight = nEndY - nY - nYOffset + 1;
            
            if ( (nWidth > 0) && (nHeight > 0) )
            {
                rc.set(nXOffset, nYOffset, nXOffset+nWidth, nYOffset+nHeight);
                
                int nWidthStart = 0;
                int nWidthEnd = 0;
                int nCurrWidth = 0;
                int nCntCopyWord = 0;
                int nYCnt = 0;
                int nLastWidth = 0;
                
                ushort wPixel;
                ushort wDyingKind, wChooseColor;
                
                // yÃà Å¬¸®ÇÎ.
                for ( nYCnt = 0; nYCnt < rc.getTop(); nYCnt++ )
                {
                    nWidthEnd += pwSrc[nWidthStart];
                    nWidthStart++;
                    nWidthEnd++;
                    nWidthStart = nWidthEnd;
                }
                
                // yÃà¿¡ ´ëÇØ¼­ ½ÇÁ¦·Î ·çÇÎ½ÃÅ³ Count¸¸À» Á¤ÇÑ´Ù.
                for ( nYCnt = rc.getTop(); nYCnt < rc.getBottom(); nYCnt++ )
                {
                    // ÇÑ¶óÀÎÀÇ ±æÀÌ¸¦ ¾ò¾î¿Â´Ù.(´ÜÀ§´Â ¿öµå)
                    nWidthEnd += pwSrc[nWidthStart];
                    nWidthStart++;
                    
                    // ¶óÀÎÀÇ ±æÀÌ¸¸Å­ È­¸é¿¡ »Ñ·ÁÁØ´Ù.
                    for ( int x = nWidthStart; x < nWidthEnd; )
                    {
                        wDyingKind = pwSrc[x];
                        if ( wDyingKind == 0xC0 )
                        {
                            x++;
                            nCntCopyWord = pwSrc[x];
                            x++;
                            nCurrWidth += nCntCopyWord;
                        }
                        else if ( wDyingKind == 0xC1 || wDyingKind == 0xC2 || wDyingKind == 0xC3 )
                        {
                            x++;
                            nCntCopyWord = pwSrc[x];
                            x++;
                            
                            nLastWidth = nCurrWidth;
                            nCurrWidth += nCntCopyWord;
                            
                            if ( rc.getLeft() > nCurrWidth || rc.getRight() < nLastWidth )
                            {
                                x += nCntCopyWord;
                            }
                            else
                            {
                                // rc.leftÁ¡À» ±âÁØÀ¸·Î Ä«ÇÇÇÒ ¿µ¿ªÀÌ °É¸° °æ¿ì.
                                if ( nLastWidth < rc.getLeft() && rc.getLeft() <= nCurrWidth )
                                {
                                    x += (rc.getLeft()-nLastWidth);
                                    memcpy(&pwDst[((nYCnt+nY) * nDstXSize) + (rc.getLeft()+nX)], &pwSrc[x], ushort.sizeof*(nCurrWidth-rc.getLeft()));
                                    x += (nCurrWidth-rc.getLeft());
                                }
                                // rc.rightÁ¡À» ±âÁØÀ¸·Î Ä«ÇÇÇÒ ¿µ¿ªÀÌ °É¸° °æ¿ì.
                                else if ( nLastWidth <= rc.getRight() && rc.getRight() < nCurrWidth )
                                {
                                    memcpy(&pwDst[((nYCnt+nY) * nDstXSize) + (nLastWidth+nX)], &pwSrc[x], ushort.sizeof*(rc.getRight()-nLastWidth));
                                    x += nCntCopyWord;
                                }
                                else
                                {
                                    memcpy(&pwDst[((nYCnt+nY) * nDstXSize) + (nLastWidth+nX)], &pwSrc[x], ushort.sizeof*nCntCopyWord);
                                    x += nCntCopyWord;
                                }
                            }
                        } 
                    }
                    // ¶óÀÎÀÇ ³¡À» ´ÙÀ½ ¶óÀÎÀÇ ½ÃÀÛÀ¸·Î ¿Å°ÜÁØ´Ù.
                    nWidthEnd++;
                    
                    nWidthStart = nWidthEnd;
                    nCurrWidth = 0;
                }
            }
            
            return true;
        }
        return false;
    }
    
    // Àû¿ëµÇ´Â ¸ÊÀÇ µ¥ÀÌÅ¸¸¦ ·Îµù.(¸ÊÀÌ ¹Ù²ð¶§¸¶´Ù ºÒ·ÁÁø´Ù.)
    public bool LoadMapData(string mapname)
    {
        File reader;
        string flname = MAPDIR ~ mapname ~ ".map";
        size_t blocksize;
        
        reader = new File;
        reader.open(flname, FileMode.In);
        if (reader.isOpen() == false)
            return false;

        FreeMapData();
        
        blocksize = reader.readBlock(&Header, Header.sizeof);
        if (blocksize != Header.sizeof)
            return false;

        immutable size_t mapsize = (Header.Width * Header.Height);
        immutable size_t correct_size = Header.sizeof + 
            (MapTileInfo.sizeof * mapsize / 4) + (MapCellInfo.sizeof * mapsize);

        assert( reader.size() == correct_size );

        TileInfoArr = new MapTileInfo[mapsize / 4];
        blocksize = reader.readBlock(&TileInfoArr[0], MapTileInfo.sizeof * mapsize / 4);

        CellInfoArr = new MapCellInfo[mapsize];
        blocksize = reader.readBlock(&CellInfoArr[0], MapCellInfo.sizeof * mapsize);

        // PDS: does not belong here in this procedure
        //LoadNewMapBuffer();
        
        reader.close();
        destroy(reader);
        
        return true;
    }

    public void LoadMapImage(ImageHandler handler)
    {
        m_pxTileImg[0]   = handler[_IMAGE_TILES];
        m_pxTileImg[1]   = handler[_IMAGE_TILES30];
        m_pxTileImg[2]   = handler[_IMAGE_TILES5];
        m_pxTileImg[3]   = handler[_IMAGE_SMTILES];
        m_pxTileImg[4]   = handler[_IMAGE_HOUSES];
        m_pxTileImg[5]   = handler[_IMAGE_CLIFFS];
        m_pxTileImg[6]   = handler[_IMAGE_DUNGEONS];
        m_pxTileImg[7]   = handler[_IMAGE_INNERS];
        m_pxTileImg[8]   = handler[_IMAGE_FUNITURES];
        m_pxTileImg[9]   = handler[_IMAGE_WALLS];
        m_pxTileImg[10]  = handler[_IMAGE_SMOBJECTS];
        m_pxTileImg[11]  = handler[_IMAGE_ANIMATIONS];
        m_pxTileImg[12]  = handler[_IMAGE_OBJECT1];
        m_pxTileImg[13]  = handler[_IMAGE_OBJECT2];
        
        m_pxTileImg[15]  = handler[_IMAGE_WOOD_TILES];
        m_pxTileImg[16]  = handler[_IMAGE_WOOD_TILES30];
        m_pxTileImg[17]  = handler[_IMAGE_WOOD_TILES5];
        m_pxTileImg[18]  = handler[_IMAGE_WOOD_SMTILES];
        m_pxTileImg[19]  = handler[_IMAGE_WOOD_HOUSES];
        m_pxTileImg[20]  = handler[_IMAGE_WOOD_CLIFFS];
        m_pxTileImg[21]  = handler[_IMAGE_WOOD_DUNGEONS];
        m_pxTileImg[22]  = handler[_IMAGE_WOOD_INNERS];
        m_pxTileImg[23]  = handler[_IMAGE_WOOD_FUNITURES];
        m_pxTileImg[24]  = handler[_IMAGE_WOOD_WALLS];
        m_pxTileImg[25]  = handler[_IMAGE_WOOD_SMOBJECTS];
        m_pxTileImg[26]  = handler[_IMAGE_WOOD_ANIMATIONS];
        m_pxTileImg[27]  = handler[_IMAGE_WOOD_OBJECT1];
        m_pxTileImg[28]  = handler[_IMAGE_WOOD_OBJECT2];
        
        m_pxTileImg[30]  = handler[_IMAGE_SAND_TILES];
        m_pxTileImg[31]  = handler[_IMAGE_SAND_TILES30];
        m_pxTileImg[32]  = handler[_IMAGE_SAND_TILES5];
        m_pxTileImg[33]  = handler[_IMAGE_SAND_SMTILES];
        m_pxTileImg[34]  = handler[_IMAGE_SAND_HOUSES];
        m_pxTileImg[35]  = handler[_IMAGE_SAND_CLIFFS];
        m_pxTileImg[36]  = handler[_IMAGE_SAND_DUNGEONS];
        m_pxTileImg[37]  = handler[_IMAGE_SAND_INNERS];
        m_pxTileImg[38]  = handler[_IMAGE_SAND_FUNITURES];
        m_pxTileImg[39]  = handler[_IMAGE_SAND_WALLS];
        m_pxTileImg[40]  = handler[_IMAGE_SAND_SMOBJECTS];
        m_pxTileImg[41]  = handler[_IMAGE_SAND_ANIMATIONS];
        m_pxTileImg[42]  = handler[_IMAGE_SAND_OBJECT1];
        m_pxTileImg[43]  = handler[_IMAGE_SAND_OBJECT2];
        
        m_pxTileImg[45]  = handler[_IMAGE_SNOW_TILES];
        m_pxTileImg[46]  = handler[_IMAGE_SNOW_TILES30];
        m_pxTileImg[47]  = handler[_IMAGE_SNOW_TILES5];
        m_pxTileImg[48]  = handler[_IMAGE_SNOW_SMTILES];
        m_pxTileImg[49]  = handler[_IMAGE_SNOW_HOUSES];
        m_pxTileImg[50]  = handler[_IMAGE_SNOW_CLIFFS];
        m_pxTileImg[51]  = handler[_IMAGE_SNOW_DUNGEONS];
        m_pxTileImg[52]  = handler[_IMAGE_SNOW_INNERS];
        m_pxTileImg[53]  = handler[_IMAGE_SNOW_FUNITURES];
        m_pxTileImg[54]  = handler[_IMAGE_SNOW_WALLS];
        m_pxTileImg[55]  = handler[_IMAGE_SNOW_SMOBJECTS];
        m_pxTileImg[56]  = handler[_IMAGE_SNOW_ANIMATIONS];
        m_pxTileImg[57]  = handler[_IMAGE_SNOW_OBJECT1];
        m_pxTileImg[58]  = handler[_IMAGE_SNOW_OBJECT2];
        
        m_pxTileImg[60]  = handler[_IMAGE_FOREST_TILES];
        m_pxTileImg[61]  = handler[_IMAGE_FOREST_TILES30];
        m_pxTileImg[62]  = handler[_IMAGE_FOREST_TILES5];
        m_pxTileImg[63]  = handler[_IMAGE_FOREST_SMTILES];
        m_pxTileImg[64]  = handler[_IMAGE_FOREST_HOUSES];
        m_pxTileImg[65]  = handler[_IMAGE_FOREST_CLIFFS];
        m_pxTileImg[66]  = handler[_IMAGE_FOREST_DUNGEONS];
        m_pxTileImg[67]  = handler[_IMAGE_FOREST_INNERS];
        m_pxTileImg[68]  = handler[_IMAGE_FOREST_FUNITURES];
        m_pxTileImg[69]  = handler[_IMAGE_FOREST_WALLS];
        m_pxTileImg[70]  = handler[_IMAGE_FOREST_SMOBJECTS];
        m_pxTileImg[71]  = handler[_IMAGE_FOREST_ANIMATIONS];
        m_pxTileImg[72]  = handler[_IMAGE_FOREST_OBJECT1];
        m_pxTileImg[73]  = handler[_IMAGE_FOREST_OBJECT2];
    }
    
    // ¸ÊÀÌ Ã³À½ ·ÎµùµÇ¾úÀ»¶§ Å¸ÀÏ, SMÅ¸ÀÏ ±â·Ï¹öÆÛ¿¡ ÃÖÃÊÀÇ ³»¿ëÀ» Àû¿ëÇÑ´Ù.
    public void LoadNewMapBuffer()
    {
        const ALLEGRO_COLOR clear_color = al_map_rgba_f(0.0, 0.0, 0.0, 0.0);
        int imgnum;
        int mx, my;
        float dx, dy;
        MapCellInfo* cell;
        ALLEGRO_BITMAP* bmp, old_target;

        // TODO:
        //m_wSavedMapBuffer = m_wSavedMapBuffer.init;
        memset(m_wSavedMapBuffer, 0, m_wSavedMapBuffer.sizeof);
        
        for ( mx = m_shStartViewTileX; mx < m_shStartViewTileX+_VIEW_CELL_X_COUNT; mx++ )
        {
            for ( my = m_shStartViewTileY; my < m_shStartViewTileY+_VIEW_CELL_Y_COUNT; my++ )
            {
                if ( mx >= Header.Width || my >= Header.Height || mx < 0 || my < 0 )
                    continue;
                
                //std.stdio.writefln("mx %s my %s", mx, my);
                DrawBaseTile(mx, my);
            }
        }

        _dirty = true;
    }
    
    // Àû¿ëµÇ´Â ¸ÊÀÇ µ¥ÀÌÅ¸¸¦ ÇØÁ¦.(¸ÊÀÌ ¹Ù²ð¶§¸¶´Ù ºÒ·ÁÁø´Ù.)
    public void FreeMapData()
    {
        Header = MapHeader.init;
        // TODO:
        //m_wSavedMapBuffer = m_wSavedMapBuffer.init;
        memset(m_wSavedMapBuffer, 0, m_wSavedMapBuffer.sizeof);

        if (CellInfoArr !is null)
        {
            destroy(CellInfoArr);
            CellInfoArr = null;
        }
    }
    
    public bool GetMapCell(int x, int y, out PMapCellInfo cell)
    {
        cell = null;
        if ((x >= 0) && (x < Header.Width) && (y >= 0) && (y < Header.Height))
        {
            cell = &CellInfoArr[x * Header.Height + y];
            return true;
        }
        return false;
    }

    public bool GetMapTile(int x, int y, out PMapTileInfo tile)
    {
        tile = null;
        if ((x >= 0) && (x < Header.Width) && (y >= 0) && (y < Header.Height))
        {
            tile = &TileInfoArr[(y / 2) + (x / 2) * Header.Height / 2];
            return true;
        }
        return false;
    }
    
    // ±âº»Å¸ÀÏÀ» ±×¸°´Ù.
    public void DrawBaseTile(int mx, int my)
    {
        // PDS: Mir2 code
        /*CellInfo* cell;
        ALLEGRO_BITMAP* bmp;
        
        float dx, dy;
        int imgnum;
        
        //if ( mx >= Header.Width || my >= Header.Height || mx < 0 || my < 0 )
        //    return; 
        if (!GetMapCell(mx, my, cell))
            return; 
        
        if( !( mx % 2 ) && !( my % 2 ) && my < m_shStartViewTileY+_VIEW_CELL_Y_COUNT )
        {
            imgnum = (cell.BkImg & 0x7FFF);
            if (imgnum > 0)
            {
                imgnum --;
                
                dx = (mx-m_shStartViewTileX)*_CELL_WIDTH;
                dy = (my-m_shStartViewTileY)*_CELL_HEIGHT;
                bmp = ImageMan[_IMAGE_TILES][imgnum];
                if (bmp !is null)
                {
                    al_draw_bitmap(bmp, dx, dy, 0);
                }
            }
        }*/

        if( !( mx % 2 ) && !( my % 2 ) && my < m_shStartViewTileY+_VIEW_CELL_Y_COUNT )
        {
            int filenum, imgnum;
            int dx, dy;
            ushort[] memory;

            filenum = TileInfoArr[(my/2) + (mx/2)*Header.Height/2].bFileIdx;
            imgnum = TileInfoArr[(my/2) + (mx/2)*Header.Height/2].wTileIdx;
            
            if ( filenum != 255 && imgnum != 65535 )
            {
                if (filenum < _MAX_TILE_FILE)
                {
                    imgnum--;
                    if (m_pxTileImg[filenum] is null) return;

                    dx = (mx-m_shStartViewTileX)*_CELL_WIDTH;
                    dy = (my-m_shStartViewTileY)*_CELL_HEIGHT;

                    memory = m_pxTileImg[filenum].GetMemory(imgnum);
                    if (memory.length > 0)
                    {
                        DrawWithImageForCompMemToMem(
                            dx,
                            dy,
                            m_pxTileImg[filenum].Info.Width,
                            m_pxTileImg[filenum].Info.Height,
                            memory,
                            _VIEW_CELL_X_COUNT*_CELL_WIDTH, _VIEW_CELL_Y_COUNT*_CELL_HEIGHT, m_wSavedMapBuffer);
                    }
                }
            }
        }
    }
    
    //  VOID            DrawOpenDoor(INT nX, INT nY);
    //  VOID            SetDoorIndex();
    
    // Ä³¸¯ÅÍ ÀÌµ¿½Ã ¸ÊÀÇ Scroll°ü·Ã º¯¼öµé Àû¿ë.
    public void ScrollMap(int direction, int frame, int speed)
    {
        frame %= 10;
        
        final switch (direction)
        {
            // Á÷¼± À§·Î ÀÌµ¿.
            case _DIRECTION_LIST_1: 
                m_shViewOffsetY = -(m_ptMovePixelArray[frame].getY() * speed);     
                break;
                // ¿À¸¥ÂÊÀ§·Î ÀÌµ¿.
            case _DIRECTION_LIST_2:
                m_shViewOffsetX =  (m_ptMovePixelArray[frame].getX() * speed);
                m_shViewOffsetY = -(m_ptMovePixelArray[frame].getY() * speed);
                break;
                // ¿À¸¥ÂÊÀ¸·Î ÀÌµ¿.
            case _DIRECTION_LIST_3:
                m_shViewOffsetX =  (m_ptMovePixelArray[frame].getX() * speed);
                break;
                // ¿À¸¥ÂÊ¾Æ·¡·Î ÀÌµ¿.
            case _DIRECTION_LIST_4:
                m_shViewOffsetX =  (m_ptMovePixelArray[frame].getX() * speed);
                m_shViewOffsetY =  (m_ptMovePixelArray[frame].getY() * speed);
                break;
                // Á÷¼± ¾Æ·¡·Î ÀÌµ¿.
            case _DIRECTION_LIST_5:
                m_shViewOffsetY =  (m_ptMovePixelArray[frame].getY() * speed);
                break;
                // ¿ÞÂÊ¾Æ·¡·Î ÀÌµ¿.
            case _DIRECTION_LIST_6:
                m_shViewOffsetX = -(m_ptMovePixelArray[frame].getX() * speed);
                m_shViewOffsetY =  (m_ptMovePixelArray[frame].getY() * speed);
                break;
                // ¿ÞÂÊÀ¸·Î ÀÌµ¿.
            case _DIRECTION_LIST_7:
                m_shViewOffsetX = -(m_ptMovePixelArray[frame].getX() * speed);
                break;
                // ¿ÞÂÊÀ§·Î ÀÌµ¿.
            case _DIRECTION_LIST_8:
                m_shViewOffsetX = -(m_ptMovePixelArray[frame].getX() * speed);
                m_shViewOffsetY = -(m_ptMovePixelArray[frame].getY() * speed);
                break;
        }
    }
    
    public void ScrollMap(int direction, int wCurrDelay, int wMoveDelay, int speed)
    {
        int nViewOffSetX = iround(((wCurrDelay+1) / cast(float)wMoveDelay) * _CELL_WIDTH ) * speed;
        int nViewOffSetY = iround(((wCurrDelay+1) / cast(float)wMoveDelay) * _CELL_HEIGHT) * speed;
        
        final switch (direction)
        {
            // Á÷¼± À§·Î ÀÌµ¿.
            case _DIRECTION_LIST_1: 
                m_shViewOffsetY -= -nViewOffSetY;
                break;
                // ¿À¸¥ÂÊÀ§·Î ÀÌµ¿.
            case _DIRECTION_LIST_2:
                m_shViewOffsetX = nViewOffSetX;
                m_shViewOffsetY = -nViewOffSetY;
                break;
                // ¿À¸¥ÂÊÀ¸·Î ÀÌµ¿.
            case _DIRECTION_LIST_3:
                m_shViewOffsetX = nViewOffSetX;
                break;
                // ¿À¸¥ÂÊ¾Æ·¡·Î ÀÌµ¿.
            case _DIRECTION_LIST_4:
                m_shViewOffsetX = nViewOffSetX;
                m_shViewOffsetY = nViewOffSetY;
                break;
                // Á÷¼± ¾Æ·¡·Î ÀÌµ¿.
            case _DIRECTION_LIST_5:
                m_shViewOffsetY = nViewOffSetY;
                break;
                // ¿ÞÂÊ¾Æ·¡·Î ÀÌµ¿.
            case _DIRECTION_LIST_6:
                m_shViewOffsetX = -nViewOffSetX;
                m_shViewOffsetY = nViewOffSetY;
                break;
                // ¿ÞÂÊÀ¸·Î ÀÌµ¿.
            case _DIRECTION_LIST_7:
                m_shViewOffsetX = -nViewOffSetX;
                break;
                // ¿ÞÂÊÀ§·Î ÀÌµ¿.
            case _DIRECTION_LIST_8:
                m_shViewOffsetX = nViewOffSetX;
                m_shViewOffsetY = -nViewOffSetY;
                break;
        }
    }
    
    // Ä³¸¯ÅÍ ÀÌµ¿½Ã »õ·Î °»½ÅµÇ´Â ±âº» ÀÌ¹ÌÁö(Å¸ÀÏ, SMÅ¸ÀÏ)¸¦ Àû¿ë.
    public void SetMovedTileBuffer(int shMovedTileX, int shMovedTileY)
    {
        m_shStartViewTileX += shMovedTileX;
        m_shStartViewTileY += shMovedTileY;
        m_shViewOffsetX = 0;
        m_shViewOffsetY = 0;

        int nX, nY, nXCnt, nYCnt;
        
        // ÇöÀç Å¸ÀÏ¹öÆÛ¿¡ ÀÖ´Â ¸Þ¸ð¸®¸¦ ¾Ë¸Â°Ô ÀÌµ¿½ÃÅ°°í Ãß°¡µÇ´Â±×¸²À» ±×¸°´Ù.
        // ¼¿´ÜÀ§°¡ ¾Æ´Ñ Å¸ÀÏ´ÜÀ§·Î ¾÷µ¥ÀÌÆ®ÇÑ´Ù.
        
        // ÇöÀç YÅ¸ÀÏÀÌ°Å³ª, ¾Æ·¡·Î °¥¶§.
        if ( shMovedTileY >= 0 )
        {
            if ( shMovedTileX >= 0 )
            {
                // ¿À¸¥ÂÊÀ¸·Î °¥¶§.
                for ( nYCnt = 0; nYCnt < _VIEW_CELL_Y_COUNT*_CELL_HEIGHT-_CELL_HEIGHT*shMovedTileY; nYCnt++ )
                {
                    memmove(&m_wSavedMapBuffer[(nYCnt*_VIEW_CELL_X_COUNT*_CELL_WIDTH)], 
                            &m_wSavedMapBuffer[((nYCnt+_CELL_HEIGHT*shMovedTileY)*_VIEW_CELL_X_COUNT*_CELL_WIDTH)+_CELL_WIDTH*shMovedTileX], 
                            ushort.sizeof*_CELL_WIDTH*(_VIEW_CELL_X_COUNT-shMovedTileX));
                }
                
                // ±×¸²»óÀ¸·Î ¿À¸¥ÂÊ°ú ¾Æ·¡ºÎºÐÀÇ Å¸ÀÏÀ» °»½ÅÇØÁà¾ßÇÑ´Ù.
                // ±âº»Å¸ÀÏÀº 2¼¿·Î ÀÌ·ïÁ®ÀÖ°í (¿À¸¥ÂÊ°ú ¾Æ·¡´Â 1¼¿¸¸ÀÇ ¿©À¯)¸¦ °¡Áö±â ¶§¹®¿¡ 1¼¿¾¿À» ´õ ÀÐ¾îÁà¼­ °»½ÅÀ» ½ÃÅ²´Ù.
                // ¾Æ·¡¿Í °°Àº ÇüÅÂÀÌ´Ù. '1'Àº memmove·Î ¿Å°ÜÁø µ¥ÀÌÅ¸ÀÌ°í 'o'°¡ »õ·Î °»½Å½ÃÅ³ Å¸ÀÏ±×¸²µ¥ÀÌÅ¸ÀÌ´Ù. '0'Àº ´õÀÐ¾îÁÙ µ¥ÀÌÅ¸ÀÌ´Ù.
                // 11111111111111...0o
                // 11111111111111...0o
                // 11111111111111...0o
                // .................0o
                // .................0o
                // 00000000000000...0o
                // oooooooooooooo...oo
                
                // ±âº»Å¸ÀÏ °»½Å.
                for ( nX = m_shStartViewTileX+_VIEW_CELL_X_COUNT-shMovedTileX-1; nX < m_shStartViewTileX+_VIEW_CELL_X_COUNT; nX++ )
                {
                    for ( nY = m_shStartViewTileY; nY < m_shStartViewTileY+_VIEW_CELL_Y_COUNT; nY++ )
                    {
                        DrawBaseTile(nX, nY);
                    }
                }
                for ( nX = m_shStartViewTileX; nX < m_shStartViewTileX+_VIEW_CELL_X_COUNT; nX++ )
                {
                    for ( nY = m_shStartViewTileY+_VIEW_CELL_Y_COUNT-shMovedTileY-1; nY < m_shStartViewTileY+_VIEW_CELL_Y_COUNT; nY++ )
                    {
                        DrawBaseTile(nX, nY);
                    }
                }
            }
            else
            {
                // ¿ÞÂÊÀ¸·Î °¥¶§.
                // ¿ÞÂÊ°ú ¾Æ·¡ºÎºÐÀÇ Å¸ÀÏÀ» °»½Å.
                // o11111111111111...1
                // o11111111111111...1
                // o11111111111111...1
                // o1................1
                // o1................1
                // o00000000000000...0
                // ooooooooooooooo...o
                
                // ±âº»Å¸ÀÏ °»½Å.
                // ÁÂÃøÀº 2Å¸ÀÏÀÇ ¿©À¯¸¦ °¡Áö¹Ç·Î 1¼¿¾¿¸¸ ÀÐ°í, ¾Æ·¡·Î´Â ÇÑÅ¸ÀÏ¸¸ÀÇ ¿©À¯¸¦ °¡Áö¹Ç·Î ¾Æ·¡·Î´Â 1¼¿¾¿À» ´õ ÀÐ¾îÁØ´Ù.
                for ( nYCnt = 0; nYCnt < _VIEW_CELL_Y_COUNT*_CELL_HEIGHT-_CELL_HEIGHT*shMovedTileY; nYCnt++ )
                {
                    memmove(&m_wSavedMapBuffer[(nYCnt*_VIEW_CELL_X_COUNT*_CELL_WIDTH)+_CELL_WIDTH*(-shMovedTileX)], 
                            &m_wSavedMapBuffer[((nYCnt+_CELL_HEIGHT*shMovedTileY)*_VIEW_CELL_X_COUNT*_CELL_WIDTH)], ushort.sizeof*_CELL_WIDTH*(_VIEW_CELL_X_COUNT-(-shMovedTileX)));
                }
                
                for ( nX = m_shStartViewTileX; nX < m_shStartViewTileX+(-shMovedTileX); nX++ )
                {
                    for ( nY = m_shStartViewTileY; nY < m_shStartViewTileY+_VIEW_CELL_Y_COUNT; nY++ )
                    {
                        DrawBaseTile(nX, nY);
                    }
                }
                for ( nX = m_shStartViewTileX; nX < m_shStartViewTileX+_VIEW_CELL_X_COUNT; nX++ )
                {
                    for ( nY = m_shStartViewTileY+_VIEW_CELL_Y_COUNT-shMovedTileY-1; nY < m_shStartViewTileY+_VIEW_CELL_Y_COUNT; nY++ )
                    {
                        DrawBaseTile(nX, nY);
                    }
                }
            }
        }
        // À§·Î °¥¶§.
        else
        {
            if ( shMovedTileX >= 0 )
            {
                // ¿À¸¥ÂÊÀ¸·Î °¥¶§.
                
                // ooooooooooooo...0o
                // 1111111111111...0o
                // ................0o
                // ................0o
                // 1111111111111...0o
                // 1111111111111...0o
                // 1111111111111...0o
                
                for ( nYCnt = (_VIEW_CELL_Y_COUNT*_CELL_HEIGHT)+(_CELL_HEIGHT*shMovedTileY)-1; nYCnt >= 0 ; nYCnt-- )
                {
                    memmove(&m_wSavedMapBuffer[((nYCnt+_CELL_HEIGHT*(-shMovedTileY))*_VIEW_CELL_X_COUNT*_CELL_WIDTH)], 
                            &m_wSavedMapBuffer[(nYCnt*_VIEW_CELL_X_COUNT*_CELL_WIDTH)+_CELL_WIDTH*shMovedTileX], ushort.sizeof*_CELL_WIDTH*(_VIEW_CELL_X_COUNT-shMovedTileX));
                }
                
                for ( nX = m_shStartViewTileX+_VIEW_CELL_X_COUNT-shMovedTileX-1; nX < m_shStartViewTileX+_VIEW_CELL_X_COUNT; nX++ )
                {
                    for ( nY = m_shStartViewTileY; nY < m_shStartViewTileY+_VIEW_CELL_Y_COUNT; nY++ )
                    {
                        DrawBaseTile(nX, nY);
                    }
                }
                for ( nX = m_shStartViewTileX; nX < m_shStartViewTileX+_VIEW_CELL_X_COUNT; nX++ )
                {
                    for ( nY = m_shStartViewTileY; nY < m_shStartViewTileY+(-shMovedTileY); nY++ )
                    {
                        DrawBaseTile(nX, nY);
                    }
                }
            }
            else
            {
                for ( nYCnt = (_VIEW_CELL_Y_COUNT*_CELL_HEIGHT)+(_CELL_HEIGHT*shMovedTileY)-1; nYCnt >= 0 ; nYCnt-- )
                {
                    // ¿ÞÂÊÀ¸·Î °¥¶§.
                    memmove(&m_wSavedMapBuffer[((nYCnt+_CELL_HEIGHT*(-shMovedTileY))*_VIEW_CELL_X_COUNT*_CELL_WIDTH)+_CELL_WIDTH*(-shMovedTileX)], 
                            &m_wSavedMapBuffer[(nYCnt*_VIEW_CELL_X_COUNT*_CELL_WIDTH)], ushort.sizeof*_CELL_WIDTH*(_VIEW_CELL_X_COUNT-(-shMovedTileX)));
                }
                
                // oooooooooooooo...o
                // o1111111111111...1
                // o1...............1
                // o1...............1
                // o1111111111111...1
                // o1111111111111...1
                // o1111111111111...1
                for ( nX = m_shStartViewTileX; nX < m_shStartViewTileX+(-shMovedTileX); nX++ )
                {
                    for ( nY = m_shStartViewTileY; nY < m_shStartViewTileY+_VIEW_CELL_Y_COUNT; nY++ )
                    {
                        DrawBaseTile(nX, nY);
                    }
                }
                for ( nX = m_shStartViewTileX; nX < m_shStartViewTileX+_VIEW_CELL_X_COUNT; nX++ )
                {
                    for ( nY = m_shStartViewTileY; nY < m_shStartViewTileY+(-shMovedTileY); nY++ )
                    {
                        DrawBaseTile(nX, nY);
                    }
                }
            }
        }

        _dirty = true;
    }
    
    // ±×¸®´Â ºä¿µ¿ªÀÇ ÃÊ±âÄ¡¼¼ÆÃ.
    public void SetStartViewTile(int nX, int nY)
    {
        m_shStartViewTileX = nX;
        m_shStartViewTileY = nY;
        m_shViewOffsetX = 0;    
        m_shViewOffsetY = 0;
    }
    
    public bool GetNextTileCanMove(int nXPos, int nYPos, int bDir, int nGap, ref IntPoint ptTarget)
    {
        int nXGapPos, nYGapPos;
        ubyte bCanMove = _CAN_WALK;
        
        nXGapPos = nYGapPos = 0;
        
        final switch ( bDir )
        {
            case _DIRECTION_LIST_1:
            {
                nXGapPos = nXPos;
                nYGapPos = nYPos-nGap;
                bCanMove  = GetTileAttribute(nXGapPos, nYGapPos);
            }
                break;
            case _DIRECTION_LIST_2:
            {
                nXGapPos = nXPos+nGap;
                nYGapPos = nYPos-nGap;
                bCanMove  = GetTileAttribute(nXGapPos, nYGapPos);
            }
                break;
            case _DIRECTION_LIST_3:
            {
                nXGapPos = nXPos+nGap;
                nYGapPos = nYPos;
                bCanMove  = GetTileAttribute(nXGapPos, nYGapPos);
            }
                break;
            case _DIRECTION_LIST_4:
            {
                nXGapPos = nXPos+nGap;
                nYGapPos = nYPos+nGap;
                bCanMove  = GetTileAttribute(nXGapPos, nYGapPos);
            }
                break;
            case _DIRECTION_LIST_5:
            {
                nXGapPos = nXPos;
                nYGapPos = nYPos+nGap;
                bCanMove  = GetTileAttribute(nXGapPos, nYGapPos);
            }
                break;
            case _DIRECTION_LIST_6:
            {
                nXGapPos = nXPos-nGap;
                nYGapPos = nYPos+nGap;
                bCanMove  = GetTileAttribute(nXGapPos, nYGapPos);
            }
                break;
            case _DIRECTION_LIST_7:
            {
                nXGapPos = nXPos-nGap;
                nYGapPos = nYPos;
                bCanMove  = GetTileAttribute(nXGapPos, nYGapPos);
            }
                break;
            case _DIRECTION_LIST_8:
            {
                nXGapPos = nXPos-nGap;
                nYGapPos = nYPos-nGap;
                bCanMove  = GetTileAttribute(nXGapPos, nYGapPos);
            }
                break;
        }

        ptTarget.set(nXGapPos, nYGapPos);
        
        if ( bCanMove != _CAN_WALK )
            return false;

        // TODO: this should not be here!
        if (PlayScene.findActorXY(nXGapPos, nYGapPos) !is null)
            return false;

        return true;
    }
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////
    public void GetScrnPosFromTilePos(int shTileX, int shTileY, ref int shScrnX, ref int shScrnY)
    {
        shScrnX = (shTileX - m_shStartViewTileX)*_CELL_WIDTH  - m_shViewOffsetX + _VIEW_CELL_X_START;
        shScrnY = (shTileY - m_shStartViewTileY)*_CELL_HEIGHT - m_shViewOffsetY + _VIEW_CELL_Y_START;
    }
    
    public void GetTilePosFromScrnPos(int shScrnX, int shScrnY, ref int shTileX, ref int shTileY)
    {
        shTileX = m_shStartViewTileX + (shScrnX - _VIEW_CELL_X_START) / _CELL_WIDTH;
        shTileY = m_shStartViewTileY + (shScrnY - _VIEW_CELL_Y_START) / _CELL_HEIGHT;
    }
    
    public ubyte CalcDirection16(int wFireTileX, int wFireTileY, int wDestTileX, int wDestTileY)
    {
        int nWidth  = wDestTileX - wFireTileX;
        int nHeight = wDestTileY - wFireTileY;
        
        float   rLineLength, rBottomInTriangle;
        int     nDimension;
        ubyte   bDir;
        rLineLength = std.math.sqrt(cast(double)(nWidth*nWidth+nHeight*nHeight));
        
        // ±âº».
        // 7  0  1          
        // 6     2
        // 5  4  3
        // ÀÏ´ÜÀº 4°³ÀÇ ºÐ¸é(90µµ±âÁØ)À¸·Î ³ª´©°í ºÐ¸é¿¡ ´ëÇÑ cos°ªÀ» Àû¿ëÇÑ´Ù.
        ( nWidth >= 0 ) ?
            ( nHeight <  0 ? (rBottomInTriangle=-nHeight, nDimension=0) : (rBottomInTriangle= nWidth, nDimension=4) ):
            ( nHeight >= 0 ? (rBottomInTriangle= nHeight, nDimension=8) : (rBottomInTriangle=-nWidth, nDimension=12) );
        // 6(cos45)  0(cos 0)  0(cos45)
        // 4(cos90)  2(cos 0)  2(cos 0)
        // 4(cos45)  2(cos90)  2(cos45)
        
        float rCosVal = rBottomInTriangle/rLineLength;
        
        const float[8] rCosVal16 = [ 1.0f, 0.980785f, 0.923880f, 0.831470f, 0.707107f, 0.555570f, 0.382683f, 0.195090f ];
        
        // °¢ºÐ¸éÀ» 3°³ÀÇ ¿µ¿ªÀ¸·Î ³ª´©¾î¼­ ¿µ¿ªÀ» ÀçÁ¶Á¤ÇÑ´Ù.
        bDir = 0;
        for ( int nCnt = 0; nCnt < 8; nCnt++ )
        {
            if( rCosVal <= rCosVal16[nCnt] )
                bDir = cast(ubyte)(nDimension + (nCnt + 1) / 2);
            else break;
        }
        
        if( bDir >= 16 ) bDir = 0;
        
        return bDir;
    }
    
    public ubyte CalcDirection8(int wFireTileX, int wFireTileY, int wDestTileX, int wDestTileY)
    {
        int nWidth  = wDestTileX - wFireTileX;
        int nHeight = wDestTileY - wFireTileY;
        
        float rLineLength, rBottomInTriangle;
        int nDimension;
        ubyte bDir;
        rLineLength = std.math.sqrt(cast(double)(nWidth*nWidth+nHeight*nHeight));
        
        // ±âº».
        // 7  0  1          
        // 6     2
        // 5  4  3
        // ÀÏ´ÜÀº 4°³ÀÇ ºÐ¸é(90µµ±âÁØ)À¸·Î ³ª´©°í ºÐ¸é¿¡ ´ëÇÑ cos°ªÀ» Àû¿ëÇÑ´Ù.
        ( nWidth >= 0 ) ?
            ( nHeight <  0 ? (rBottomInTriangle=-nHeight, nDimension=0) : (rBottomInTriangle= nWidth, nDimension=2) ):
            ( nHeight >= 0 ? (rBottomInTriangle= nHeight, nDimension=4) : (rBottomInTriangle=-nWidth, nDimension=6) );
        // 6(cos45)  0(cos 0)  0(cos45)
        // 4(cos90)  2(cos 0)  2(cos 0)
        // 4(cos45)  2(cos90)  2(cos45)
        
        float rCosVal = rBottomInTriangle/rLineLength;
        
        //  cos(0), cos(pi/8), cos(pi/4), cos(pi/2)
        const float[4] rCosVal8 = [ 1.0f, 0.923880f, 0.707107f, 0.382683f ];
        
        // °¢ºÐ¸éÀ» 3°³ÀÇ ¿µ¿ªÀ¸·Î ³ª´©¾î¼­ ¿µ¿ªÀ» ÀçÁ¶Á¤ÇÑ´Ù.
        bDir = 0;
        for ( int nCnt = 0; nCnt < 4; nCnt++ )
        {
            if ( rCosVal <= rCosVal8[nCnt] )
                bDir = cast(ubyte)(nDimension + (nCnt + 1) / 2);
            else break;
        }
        
        if ( bDir >= 8 ) bDir = 0;
        
        return bDir;
    }
    
    
    //  ÇöÀç Å¸ÀÏ¿¡ ´ëÇÑ ¸Ê¼Ó¼º ¾ò±â ÇÔ¼öµé.
    public ubyte GetTileAttribute(int nX, int nY)
    {
        PMapCellInfo cell;
        ubyte bAttr = _CAN_NOTWALK;

        if (GetMapCell(nX, nY, cell))
        {
            if ( cell.bFlag & 0X01 )
                bAttr = _CAN_WALK;
        }
        
        return bAttr;
    }

    public int GetEventNum(int nX, int nY)
    {
        PMapCellInfo cell;
        int bEventNum = -1;

        if (GetMapCell(nX, nY, cell))
        {
            if ( (cell.wLigntNEvent == -1) && ((cell.wLigntNEvent & 0X07) != 3) )
                return bEventNum;
            
            bEventNum = ((cell.wLigntNEvent & 0XF0) >> 4);
        }
        
        return bEventNum;
    }

    /+
    public bool GetDoorState(int nX, int nY)
    {
        PMapCellInfo cell;

        if ( (nX == 432 || nX == 433) && (nY == 70 || nY == 71 ||nY == 72 ) )
            int a = 0;

        if (GetMapCell(nX, nY, cell))
        {
            if ( (cell.wLigntNEvent == 65535) || !(cell.wLigntNEvent & 0X08) )
                return false;
        }
        
        // ¹®ÀÌ¿­·ÁÀÖ´Ù.
        return true;
    }
    +/

    /+
    public void SetDoorState(ubyte bIndex, bool bDoorOpen)
    {
        PMapCellInfo cell;
        int nCnt, nLoop;
        ushort wPosX, wPosY;

        for ( nCnt = 0; nCnt < m_bDoorCount; nCnt++ )
        {
            if ( m_pstDoorInfo[nCnt].bDoorIdx == bIndex )
            {
                for ( nLoop = 0; nLoop < m_pstDoorInfo[nCnt].bDoorImgCnt; nLoop++ )
                {
                    wPosX = m_pstDoorInfo[nCnt].pstDoorImgInfo[nLoop].wPosX;
                    wPosY = m_pstDoorInfo[nCnt].pstDoorImgInfo[nLoop].wPosY;

                    if (GetMapCell(wPosX, wPosY, cell))
                    {
                        if ( bDoorOpen )
                            cell.wLigntNEvent = cell.wLigntNEvent | 0X08;
                        else
                            cell.wLigntNEvent = cell.wLigntNEvent & 0XFFF7;
                    }
                }
            }
        }
    }
    +/

    public int GetDoor(int nX, int nY)
    {
        PMapCellInfo cell;
        int door = 0;

        if (GetMapCell(nX, nY, cell))
        {
            if ( (cell.DoorIndex & 0X80) > 0 )
            {
                door = cell.DoorIndex & 0X7F;
            }
        }
        
        return door;
    }

    public void OpenDoor(int nX, int nY, int nIdx)
    {
        PMapCellInfo cell;
        int nCntX, nCntY;

        for ( nCntY = nY-8; nCntY < nY+10; nCntY++ )
        {
            for ( nCntX = nX-8; nCntX < nX+10; nCntX++ )
            {
                if (GetMapCell(nCntX, nCntY, cell))
                {
                    if ( (cell.DoorIndex & 0X7F) == nIdx )
                    {
                        cell.DoorOffset |= 0X80;
                    }
                }
            }
        }
    }

    public void CloseDoor(int nX, int nY, int nIdx)
    {
        PMapCellInfo cell;
        int nCntX, nCntY;

        for ( nCntY = nY-8; nCntY < nY+10; nCntY++ )
        {
            for ( nCntX = nX-8; nCntX < nX+10; nCntX++ )
            {
                if (GetMapCell(nCntX, nCntY, cell))
                {
                    if ( (cell.DoorIndex & 0X7F) == nIdx )
                    {
                        cell.DoorOffset &= 0X7F;
                    }
                }
            }
        }
    }

    public int GetDoorImgIdx(int nX, int nY)
    {
        PMapCellInfo cell;
        int door = 0;

        if (GetMapCell(nX, nY, cell))
        {
            /*if ( (cell.DoorOffset & 0X80) > 0 )
            {
                if ( (cell.DoorIndex & 0X7F) > 0 )
                    door = cell.DoorOffset & 0X7F;
            }*/
            if ( (cell.DoorIndex & 0X80) > 0 )
            {
                door += cell.DoorIndex & 0X7F;
            }
        }
        
        return door;
    }

    public bool IsDoorOpen(int nX, int nY)
    {
        PMapCellInfo cell;

        if (GetMapCell(nX, nY, cell))
        {
            if ( (cell.DoorIndex & 0X80) > 0 )
            {
                if ( (cell.DoorOffset & 0X80) == 0 )
                {
                    return false;
                }
            }
        }
        return true;
    }
    
    public LightInfo GetTileLightInfo(int nX, int nY)
    {
        PMapCellInfo cell;
        LightInfo light = { false, -1, -1 };

        if (GetMapCell(nX, nY, cell))
        {
            if ( (cell.wLigntNEvent == 0) && 
                ((cell.wLigntNEvent & 0X07) != 1) )
                return light;
            
            light.IsLight        = true;
            light.LightSizeType  = ((cell.wLigntNEvent & 0XC000) >> 14);
            light.LightColorType = ((cell.wLigntNEvent & 0X3FF0) >> 4);
        }
        
        return light;
    }

    public void SetAniTileFrame(int nLoopTime)
    {
        int nCnt;

        void SetFrame(int index, uint delay)
        {
            if ( m_dwAniSaveTime[index] > delay )
            {
                for ( nCnt = 0; nCnt < 16; nCnt++ )
                {
                    m_bAniTileFrame[index][nCnt]++;
                    
                    if ( m_bAniTileFrame[index][nCnt] >= nCnt )
                        m_bAniTileFrame[index][nCnt] = 0;
                }
                m_dwAniSaveTime[index] = 0;
            }
        }

        
        for ( nCnt = 0; nCnt < 8; nCnt++ )
        {
            m_dwAniSaveTime[nCnt] += nLoopTime;
        }

        SetFrame( 0, _TILE_ANI_DELAY_1 );
        SetFrame( 1, _TILE_ANI_DELAY_2 );
        SetFrame( 2, _TILE_ANI_DELAY_3 );
        SetFrame( 3, _TILE_ANI_DELAY_4 );
        SetFrame( 4, _TILE_ANI_DELAY_5 );
        SetFrame( 5, _TILE_ANI_DELAY_6 );
        SetFrame( 6, _TILE_ANI_DELAY_7 );
        SetFrame( 7, _TILE_ANI_DELAY_8 );
    }

    @property public bool isDirty() { return _dirty; }
    @property public void setDirty(bool value) { _dirty = value; }
}
























//  VOID            DrawOneCellObjTile(INT nX, INT nY);
//  BOOL            DrawOneCellOverObjTile(INT nX, INT nY);

